﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;

namespace Emico.Linq.Criterion
{
    [Serializable]
    public abstract class ContainExpression<T, TValue> : AbstractExpression<T>
        where T : class
    {
        #region Properties

        public string PropertyName
        {
            get;
            private set;
        }

        public IEnumerable<TValue> Values
        {
            get;
            private set;
        }

        #endregion

        public ContainExpression(string propertyName, IEnumerable<TValue> values)
        {
            if (string.IsNullOrWhiteSpace(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }

            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            if (!values.Any())
            {
                throw new ArgumentException("at least one", "values");
            }

            this.PropertyName = propertyName;
            this.Values = values;
        }

        public ContainExpression(Expression<Func<T, TValue>> selector, IEnumerable<TValue> values)
            : this(new PropertyPathVisitor().GetPropertyPath(selector), values)
        {
        }

        protected ContainExpression(SerializationInfo info, StreamingContext context)
        {
            this.Values = (IEnumerable<TValue>)info.GetValue("Values", typeof(IEnumerable<TValue>));
            this.PropertyName = info.GetString("PropertyName");
        }

        #region Implement Abstract Method

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Values", this.Values);
            info.AddValue("PropertyName", this.PropertyName);
        }

        #endregion
    }
}
